{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "#  Copyright (c) Microsoft Corporation.\n",
    "#  Licensed under the MIT License.\n",
    "\n",
    "# -*- coding: utf-8 -*-\n",
    "# @Author   : Yi Li (liyi_best@foxmail.com)\n",
    "# @Time     : 2022/8/24 8:49\n",
    "# @File     : 快速入门.ipynb\n",
    "# @Project  : ai_quant_trade\n",
    "# Copyright (c) Personal 2022 Yi Li\n",
    "# Function Description: Fast tutorial for qlib\n",
    "#\n",
    "# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
    "# you may not use this file except in compliance with the License.\n",
    "# You may obtain a copy of the License at\n",
    "#\n",
    "#     http://www.apache.org/licenses/LICENSE-2.0\n",
    "#\n",
    "# Unless required by applicable law or agreed to in writing, software\n",
    "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
    "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
    "# See the License for the specific language governing permissions and\n",
    "# limitations under the License.\n",
    "\n",
    "#  本样例基于qlib/examples/workflow_by_code.py，进行了小修改和注释加入\n",
    "#  本样例仅是一个快速入门样例，详细使用查看后续章节"
   ]
  },
  {
   "cell_type": "markdown",
   "source": [
    "# 1. 数据下载\n",
    "* 通过qlib库获取数据：from qlib.tests.data import GetData\n",
    "* 数据从微软官网获取：REMOTE_URL = \"http://fintech.msra.cn/stock_data/downloads\"\n",
    "* 下载后默认存放在\"~/.qlib/qlib_data/cn_data\"\n",
    "* 压缩包命名格式：20220701081835_qlib_data_simple_cn_1d_latest\n",
    "* 之后自动解压"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   }
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[26088:MainThread](2022-09-13 22:30:44,307) INFO - qlib.Initialization - [config.py:402] - default_conf: client.\n",
      "[26088:MainThread](2022-09-13 22:30:44,310) INFO - qlib.Initialization - [__init__.py:74] - qlib successfully initialized based on client settings.\n",
      "[26088:MainThread](2022-09-13 22:30:44,311) INFO - qlib.Initialization - [__init__.py:76] - data_path={'__DEFAULT_FREQ': WindowsPath('C:/Users/pc/.qlib/qlib_data/cn_data')}\n"
     ]
    }
   ],
   "source": [
    "import qlib\n",
    "import pandas as pd\n",
    "from qlib.constant import REG_CN\n",
    "from qlib.utils import exists_qlib_data, init_instance_by_config\n",
    "from qlib.workflow import R\n",
    "from qlib.workflow.record_temp import SignalRecord, PortAnaRecord\n",
    "from qlib.utils import flatten_dict\n",
    "\n",
    "# use default data\n",
    "# NOTE: 也可以通过qlib源码运行获取数据: python scripts/get_data.py qlib_data_cn --target_dir ~/.qlib/qlib_data/cn_data\n",
    "provider_uri = \"~/.qlib/qlib_data/cn_data\"  # target_dir\n",
    "if not exists_qlib_data(provider_uri):\n",
    "    print(f\"Qlib data is not found in {provider_uri}\")\n",
    "    # sys.path.append(str(scripts_dir))\n",
    "    from qlib.tests.data import GetData\n",
    "    GetData().qlib_data(target_dir=provider_uri, region=REG_CN)\n",
    "qlib.init(provider_uri=provider_uri, region=REG_CN)"
   ],
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   }
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2. 模型训练\n",
    "注意：不太友好的一点，数据加载过程没有进度条，如果数据多，加载过程可能稍长\n",
    "* 对基本数据，计算技术指标，获取alpha158因子\n",
    "* 使用LightGBM，进行回归预测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# market未选股的股票池，benchmark为参考的指数基准\n",
    "market = \"csi300\"  # 沪深300股票池代码，在instruments文件夹下有对应的csi300.txt\n",
    "benchmark = \"SH000300\"   # 沪深300指数\n",
    "\n",
    "# 数据配置信息\n",
    "#  start/end是总数据时间段，包含训练和测试\n",
    "#  fit是train/valid的时间\n",
    "data_handler_config = {\n",
    "    \"start_time\": \"2008-01-01\",\n",
    "    \"end_time\": \"2020-08-01\",\n",
    "    \"fit_start_time\": \"2008-01-01\",\n",
    "    \"fit_end_time\": \"2014-12-31\",\n",
    "    \"instruments\": market,\n",
    "}\n",
    "\n",
    "# 模型及数据配置信息\n",
    "# qlib.contrib.model.gbdt继承了qlib/model/base.py\n",
    "task = {\n",
    "    \"model\": {\n",
    "        \"class\": \"LGBModel\",\n",
    "        \"module_path\": \"qlib.contrib.model.gbdt\",\n",
    "        \"kwargs\": {\n",
    "            \"loss\": \"mse\",\n",
    "            \"colsample_bytree\": 0.8879,\n",
    "            \"learning_rate\": 0.0421,\n",
    "            \"subsample\": 0.8789,\n",
    "            \"lambda_l1\": 205.6999,\n",
    "            \"lambda_l2\": 580.9768,\n",
    "            \"max_depth\": 8,\n",
    "            \"num_leaves\": 210,\n",
    "            \"num_threads\": 20,\n",
    "        },\n",
    "    },\n",
    "    \"dataset\": {\n",
    "        \"class\": \"DatasetH\",\n",
    "        \"module_path\": \"qlib.data.dataset\",\n",
    "        \"kwargs\": {\n",
    "            \"handler\": {\n",
    "                \"class\": \"Alpha158\",\n",
    "                \"module_path\": \"qlib.contrib.data.handler\",\n",
    "                \"kwargs\": data_handler_config,\n",
    "            },\n",
    "            \"segments\": {\n",
    "                \"train\": (\"2008-01-01\", \"2014-12-31\"),\n",
    "                \"valid\": (\"2015-01-01\", \"2016-12-31\"),\n",
    "                \"test\": (\"2017-01-01\", \"2020-08-01\"),\n",
    "            },\n",
    "        },\n",
    "    },\n",
    "}\n",
    "\n",
    "# 数据和模型初始化\n",
    "# 使用上面json中定义的模块路径和名称初始化类\n",
    "model = init_instance_by_config(task[\"model\"])\n",
    "dataset = init_instance_by_config(task[\"dataset\"])\n",
    "\n",
    "# start exp to train model, 通过R控制流程\n",
    "with R.start(experiment_name=\"train_model\"):\n",
    "    R.log_params(**flatten_dict(task))\n",
    "    model.fit(dataset)\n",
    "    R.save_objects(trained_model=model)\n",
    "    rid = R.get_recorder().id  # 获取id"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 3. 预测, 回测 & 分析\n",
    "如下json中：\n",
    "* backtest：设置回测的时间段、账户信息和各种费用等回测条件\n",
    "* executor：选择了模拟交易，按天执行，根据策略信号进行执行\n",
    "* strategy: 给出决策，TopkDropoutStrategy，即基于模型对所有股票预测的得分，\n",
    "  买入前k支股票，卖掉持仓的N支股票\n",
    "\n",
    "计算时，会导入交易日的txt文件（详见数据描述的文档），根据测试日期获取\n",
    "索引位置，之后按索引位置顺序执行模拟交易，用交易日减最小数据单位（即1日），\n",
    "模型用前一天的值进行预测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[12372:MainThread](2022-09-02 08:07:10,533) INFO - qlib.workflow - [expm.py:315] - <mlflow.tracking.client.MlflowClient object at 0x00000230AFF34EE0>\n",
      "[12372:MainThread](2022-09-02 08:07:10,554) WARNING - qlib.workflow - [expm.py:195] - No valid experiment found. Create a new experiment with name backtest_analysis.\n",
      "[12372:MainThread](2022-09-02 08:07:10,568) INFO - qlib.workflow - [exp.py:257] - Experiment 2 starts running ...\n",
      "[12372:MainThread](2022-09-02 08:07:10,637) INFO - qlib.workflow - [recorder.py:293] - Recorder 4631afb3c47a4277b5e937a89fc9e9e4 starts running under Experiment 2 ...\n",
      "[12372:MainThread](2022-09-02 08:07:12,517) INFO - qlib.workflow - [record_temp.py:194] - Signal record 'pred.pkl' has been saved as the artifact of the Experiment 2\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "'The following are prediction results of the LGBModel model.'\n",
      "                          score\n",
      "datetime   instrument          \n",
      "2017-01-03 SH600000   -0.036180\n",
      "           SH600008    0.012532\n",
      "           SH600009    0.036990\n",
      "           SH600010   -0.020218\n",
      "           SH600015   -0.129913\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[12372:MainThread](2022-09-02 08:07:12,678) INFO - qlib.backtest caller - [__init__.py:83] - Create new exchange\n",
      "[12372:MainThread](2022-09-02 08:13:11,120) WARNING - qlib.BaseExecutor - [executor.py:111] - `common_infra` is not set for <qlib.backtest.executor.SimulatorExecutor object at 0x00000230AFF453D0>\n"
     ]
    },
    {
     "data": {
      "text/plain": "backtest loop:   0%|          | 0/871 [00:00<?, ?it/s]",
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "912f864798fc415dafa091c770728572"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "D:\\Users\\pc\\anaconda3\\lib\\site-packages\\qlib\\utils\\index_data.py:480: RuntimeWarning: Mean of empty slice\n",
      "  return np.nanmean(self.data)\n"
     ]
    },
    {
     "ename": "KeyboardInterrupt",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[1;31mKeyboardInterrupt\u001B[0m                         Traceback (most recent call last)",
      "\u001B[1;32m<ipython-input-5-b3f19fc0de8f>\u001B[0m in \u001B[0;36m<module>\u001B[1;34m\u001B[0m\n\u001B[0;32m     51\u001B[0m     \u001B[1;31m# backtest & analysis\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m     52\u001B[0m     \u001B[0mpar\u001B[0m \u001B[1;33m=\u001B[0m \u001B[0mPortAnaRecord\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mrecorder\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mport_analysis_config\u001B[0m\u001B[1;33m,\u001B[0m \u001B[1;34m\"day\"\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m---> 53\u001B[1;33m     \u001B[0mpar\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mgenerate\u001B[0m\u001B[1;33m(\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m\u001B[0;32m     54\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m     55\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n",
      "\u001B[1;32mD:\\Users\\pc\\anaconda3\\lib\\site-packages\\qlib\\workflow\\record_temp.py\u001B[0m in \u001B[0;36mgenerate\u001B[1;34m(self, *args, **kwargs)\u001B[0m\n\u001B[0;32m    230\u001B[0m             \u001B[0mlogger\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mwarning\u001B[0m\u001B[1;33m(\u001B[0m\u001B[1;34m\"The dependent data does not exists. Generation skipped.\"\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m    231\u001B[0m             \u001B[1;32mreturn\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m--> 232\u001B[1;33m         \u001B[1;32mreturn\u001B[0m \u001B[0mself\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0m_generate\u001B[0m\u001B[1;33m(\u001B[0m\u001B[1;33m*\u001B[0m\u001B[0margs\u001B[0m\u001B[1;33m,\u001B[0m \u001B[1;33m**\u001B[0m\u001B[0mkwargs\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m\u001B[0;32m    233\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m    234\u001B[0m     \u001B[1;32mdef\u001B[0m \u001B[0m_generate\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mself\u001B[0m\u001B[1;33m,\u001B[0m \u001B[1;33m*\u001B[0m\u001B[0margs\u001B[0m\u001B[1;33m,\u001B[0m \u001B[1;33m**\u001B[0m\u001B[0mkwargs\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m:\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n",
      "\u001B[1;32mD:\\Users\\pc\\anaconda3\\lib\\site-packages\\qlib\\workflow\\record_temp.py\u001B[0m in \u001B[0;36m_generate\u001B[1;34m(self, **kwargs)\u001B[0m\n\u001B[0;32m    466\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m    467\u001B[0m         \u001B[1;31m# custom strategy and get backtest\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m--> 468\u001B[1;33m         portfolio_metric_dict, indicator_dict = normal_backtest(\n\u001B[0m\u001B[0;32m    469\u001B[0m             \u001B[0mexecutor\u001B[0m\u001B[1;33m=\u001B[0m\u001B[0mself\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mexecutor_config\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mstrategy\u001B[0m\u001B[1;33m=\u001B[0m\u001B[0mself\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mstrategy_config\u001B[0m\u001B[1;33m,\u001B[0m \u001B[1;33m**\u001B[0m\u001B[0mself\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mbacktest_config\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m    470\u001B[0m         )\n",
      "\u001B[1;32mD:\\Users\\pc\\anaconda3\\lib\\site-packages\\qlib\\backtest\\__init__.py\u001B[0m in \u001B[0;36mbacktest\u001B[1;34m(start_time, end_time, strategy, executor, benchmark, account, exchange_kwargs, pos_type)\u001B[0m\n\u001B[0;32m    253\u001B[0m         \u001B[0mpos_type\u001B[0m\u001B[1;33m=\u001B[0m\u001B[0mpos_type\u001B[0m\u001B[1;33m,\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m    254\u001B[0m     )\n\u001B[1;32m--> 255\u001B[1;33m     \u001B[0mportfolio_metrics\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mindicator\u001B[0m \u001B[1;33m=\u001B[0m \u001B[0mbacktest_loop\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mstart_time\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mend_time\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mtrade_strategy\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mtrade_executor\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m\u001B[0;32m    256\u001B[0m     \u001B[1;32mreturn\u001B[0m \u001B[0mportfolio_metrics\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mindicator\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m    257\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n",
      "\u001B[1;32mD:\\Users\\pc\\anaconda3\\lib\\site-packages\\qlib\\backtest\\backtest.py\u001B[0m in \u001B[0;36mbacktest_loop\u001B[1;34m(start_time, end_time, trade_strategy, trade_executor)\u001B[0m\n\u001B[0;32m     26\u001B[0m     \"\"\"\n\u001B[0;32m     27\u001B[0m     \u001B[0mreturn_value\u001B[0m \u001B[1;33m=\u001B[0m \u001B[1;33m{\u001B[0m\u001B[1;33m}\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m---> 28\u001B[1;33m     \u001B[1;32mfor\u001B[0m \u001B[0m_decision\u001B[0m \u001B[1;32min\u001B[0m \u001B[0mcollect_data_loop\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mstart_time\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mend_time\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mtrade_strategy\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mtrade_executor\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mreturn_value\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m:\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m\u001B[0;32m     29\u001B[0m         \u001B[1;32mpass\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m     30\u001B[0m     \u001B[1;32mreturn\u001B[0m \u001B[0mreturn_value\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mget\u001B[0m\u001B[1;33m(\u001B[0m\u001B[1;34m\"portfolio_metrics\"\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mreturn_value\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mget\u001B[0m\u001B[1;33m(\u001B[0m\u001B[1;34m\"indicator\"\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n",
      "\u001B[1;32mD:\\Users\\pc\\anaconda3\\lib\\site-packages\\qlib\\backtest\\backtest.py\u001B[0m in \u001B[0;36mcollect_data_loop\u001B[1;34m(start_time, end_time, trade_strategy, trade_executor, return_value)\u001B[0m\n\u001B[0;32m     63\u001B[0m         \u001B[0m_execute_result\u001B[0m \u001B[1;33m=\u001B[0m \u001B[1;32mNone\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m     64\u001B[0m         \u001B[1;32mwhile\u001B[0m \u001B[1;32mnot\u001B[0m \u001B[0mtrade_executor\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mfinished\u001B[0m\u001B[1;33m(\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m:\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m---> 65\u001B[1;33m             \u001B[0m_trade_decision\u001B[0m\u001B[1;33m:\u001B[0m \u001B[0mBaseTradeDecision\u001B[0m \u001B[1;33m=\u001B[0m \u001B[0mtrade_strategy\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mgenerate_trade_decision\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0m_execute_result\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m\u001B[0;32m     66\u001B[0m             \u001B[0m_execute_result\u001B[0m \u001B[1;33m=\u001B[0m \u001B[1;32myield\u001B[0m \u001B[1;32mfrom\u001B[0m \u001B[0mtrade_executor\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mcollect_data\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0m_trade_decision\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mlevel\u001B[0m\u001B[1;33m=\u001B[0m\u001B[1;36m0\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m     67\u001B[0m             \u001B[0mbar\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mupdate\u001B[0m\u001B[1;33m(\u001B[0m\u001B[1;36m1\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n",
      "\u001B[1;32mD:\\Users\\pc\\anaconda3\\lib\\site-packages\\qlib\\contrib\\strategy\\signal_strategy.py\u001B[0m in \u001B[0;36mgenerate_trade_decision\u001B[1;34m(self, execute_result)\u001B[0m\n\u001B[0;32m    210\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m    211\u001B[0m         \u001B[1;31m# Get the stock list we really want to buy\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m--> 212\u001B[1;33m         \u001B[0mbuy\u001B[0m \u001B[1;33m=\u001B[0m \u001B[0mtoday\u001B[0m\u001B[1;33m[\u001B[0m\u001B[1;33m:\u001B[0m \u001B[0mlen\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0msell\u001B[0m\u001B[1;33m)\u001B[0m \u001B[1;33m+\u001B[0m \u001B[0mself\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mtopk\u001B[0m \u001B[1;33m-\u001B[0m \u001B[0mlen\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mlast\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m]\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m\u001B[0;32m    213\u001B[0m         \u001B[1;32mfor\u001B[0m \u001B[0mcode\u001B[0m \u001B[1;32min\u001B[0m \u001B[0mcurrent_stock_list\u001B[0m\u001B[1;33m:\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m    214\u001B[0m             if not self.trade_exchange.is_stock_tradable(\n",
      "\u001B[1;32mD:\\Users\\pc\\anaconda3\\lib\\site-packages\\qlib\\contrib\\strategy\\signal_strategy.py\u001B[0m in \u001B[0;36mgenerate_trade_decision\u001B[1;34m(self, execute_result)\u001B[0m\n\u001B[0;32m    210\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m    211\u001B[0m         \u001B[1;31m# Get the stock list we really want to buy\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m--> 212\u001B[1;33m         \u001B[0mbuy\u001B[0m \u001B[1;33m=\u001B[0m \u001B[0mtoday\u001B[0m\u001B[1;33m[\u001B[0m\u001B[1;33m:\u001B[0m \u001B[0mlen\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0msell\u001B[0m\u001B[1;33m)\u001B[0m \u001B[1;33m+\u001B[0m \u001B[0mself\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mtopk\u001B[0m \u001B[1;33m-\u001B[0m \u001B[0mlen\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mlast\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m]\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m\u001B[0;32m    213\u001B[0m         \u001B[1;32mfor\u001B[0m \u001B[0mcode\u001B[0m \u001B[1;32min\u001B[0m \u001B[0mcurrent_stock_list\u001B[0m\u001B[1;33m:\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m    214\u001B[0m             if not self.trade_exchange.is_stock_tradable(\n",
      "\u001B[1;32m_pydevd_bundle\\pydevd_cython_win32_38_64.pyx\u001B[0m in \u001B[0;36m_pydevd_bundle.pydevd_cython_win32_38_64.SafeCallWrapper.__call__\u001B[1;34m()\u001B[0m\n",
      "\u001B[1;32m_pydevd_bundle\\pydevd_cython_win32_38_64.pyx\u001B[0m in \u001B[0;36m_pydevd_bundle.pydevd_cython_win32_38_64.PyDBFrame.trace_dispatch\u001B[1;34m()\u001B[0m\n",
      "\u001B[1;32m_pydevd_bundle\\pydevd_cython_win32_38_64.pyx\u001B[0m in \u001B[0;36m_pydevd_bundle.pydevd_cython_win32_38_64.PyDBFrame.trace_dispatch\u001B[1;34m()\u001B[0m\n",
      "\u001B[1;32m_pydevd_bundle\\pydevd_cython_win32_38_64.pyx\u001B[0m in \u001B[0;36m_pydevd_bundle.pydevd_cython_win32_38_64.PyDBFrame.trace_dispatch\u001B[1;34m()\u001B[0m\n",
      "\u001B[1;32m_pydevd_bundle\\pydevd_cython_win32_38_64.pyx\u001B[0m in \u001B[0;36m_pydevd_bundle.pydevd_cython_win32_38_64.PyDBFrame.do_wait_suspend\u001B[1;34m()\u001B[0m\n",
      "\u001B[1;32mD:\\Program Files\\JetBrains\\PyCharm 2021.2.3\\plugins\\python\\helpers\\pydev\\pydevd.py\u001B[0m in \u001B[0;36mdo_wait_suspend\u001B[1;34m(self, thread, frame, event, arg, send_suspend_message, is_unhandled_exception)\u001B[0m\n\u001B[0;32m   1145\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m   1146\u001B[0m         \u001B[1;32mwith\u001B[0m \u001B[0mself\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0m_threads_suspended_single_notification\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mnotify_thread_suspended\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mthread_id\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mstop_reason\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m:\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m-> 1147\u001B[1;33m             \u001B[0mself\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0m_do_wait_suspend\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mthread\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mframe\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mevent\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0marg\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0msuspend_type\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mfrom_this_thread\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m\u001B[0;32m   1148\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m   1149\u001B[0m     \u001B[1;32mdef\u001B[0m \u001B[0m_do_wait_suspend\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mself\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mthread\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mframe\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mevent\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0marg\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0msuspend_type\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mfrom_this_thread\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m:\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n",
      "\u001B[1;32mD:\\Program Files\\JetBrains\\PyCharm 2021.2.3\\plugins\\python\\helpers\\pydev\\pydevd.py\u001B[0m in \u001B[0;36m_do_wait_suspend\u001B[1;34m(self, thread, frame, event, arg, suspend_type, from_this_thread)\u001B[0m\n\u001B[0;32m   1160\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m   1161\u001B[0m                 \u001B[0mself\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mprocess_internal_commands\u001B[0m\u001B[1;33m(\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m-> 1162\u001B[1;33m                 \u001B[0mtime\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0msleep\u001B[0m\u001B[1;33m(\u001B[0m\u001B[1;36m0.01\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m\u001B[0;32m   1163\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m   1164\u001B[0m         \u001B[0mself\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mcancel_async_evaluation\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mget_current_thread_id\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mthread\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mstr\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mid\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mframe\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n",
      "\u001B[1;31mKeyboardInterrupt\u001B[0m: "
     ]
    }
   ],
   "source": [
    "###################################\n",
    "# prediction, backtest & analysis\n",
    "###################################\n",
    "port_analysis_config = {\n",
    "    \"executor\": {\n",
    "        \"class\": \"SimulatorExecutor\",\n",
    "        \"module_path\": \"qlib.backtest.executor\",\n",
    "        \"kwargs\": {\n",
    "            \"time_per_step\": \"day\",\n",
    "            \"generate_portfolio_metrics\": True,\n",
    "        },\n",
    "    },\n",
    "    \"strategy\": {\n",
    "        \"class\": \"TopkDropoutStrategy\",\n",
    "        \"module_path\": \"qlib.contrib.strategy.signal_strategy\",\n",
    "        \"kwargs\": {\n",
    "            \"model\": model,\n",
    "            \"dataset\": dataset,\n",
    "            \"topk\": 50,\n",
    "            \"n_drop\": 5,\n",
    "        },\n",
    "    },\n",
    "    \"backtest\": {\n",
    "        \"start_time\": \"2017-01-01\",\n",
    "        \"end_time\": \"2020-08-01\",\n",
    "        \"account\": 100000000,\n",
    "        \"benchmark\": benchmark,\n",
    "        \"exchange_kwargs\": {\n",
    "            \"freq\": \"day\",\n",
    "            \"limit_threshold\": 0.095,\n",
    "            \"deal_price\": \"close\",\n",
    "            \"open_cost\": 0.0005,\n",
    "            \"close_cost\": 0.0015,\n",
    "            \"min_cost\": 5,\n",
    "        },\n",
    "    },\n",
    "}\n",
    "\n",
    "# backtest and analysis\n",
    "with R.start(experiment_name=\"backtest_analysis\"):\n",
    "    recorder = R.get_recorder(recorder_id=rid, experiment_name=\"train_model\")\n",
    "    model = recorder.load_object(\"trained_model\")\n",
    "\n",
    "    # prediction\n",
    "    recorder = R.get_recorder()\n",
    "    ba_rid = recorder.id\n",
    "    sr = SignalRecord(model, dataset, recorder)\n",
    "    sr.generate()\n",
    "\n",
    "    # backtest & analysis\n",
    "    par = PortAnaRecord(recorder, port_analysis_config, \"day\")\n",
    "    par.generate()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# analyze graphs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from qlib.contrib.report import analysis_model, analysis_position\n",
    "from qlib.data import D\n",
    "recorder = R.get_recorder(recorder_id=ba_rid, experiment_name=\"backtest_analysis\")\n",
    "print(recorder)\n",
    "pred_df = recorder.load_object(\"pred.pkl\")\n",
    "report_normal_df = recorder.load_object(\"portfolio_analysis/report_normal_1day.pkl\")\n",
    "positions = recorder.load_object(\"portfolio_analysis/positions_normal_1day.pkl\")\n",
    "analysis_df = recorder.load_object(\"portfolio_analysis/port_analysis_1day.pkl\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## analysis position"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### report"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "analysis_position.report_graph(report_normal_df)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### risk analysis"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "analysis_position.risk_analysis_graph(analysis_df, report_normal_df)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## analysis model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "label_df = dataset.prepare(\"test\", col_set=\"label\")\n",
    "label_df.columns = ['label']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### score IC"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pred_label = pd.concat([label_df, pred_df], axis=1, sort=True).reindex(label_df.index)\n",
    "analysis_position.score_ic_graph(pred_label)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### model performance"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "analysis_model.model_performance_graph(pred_label)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "name": "pycharm-5ee6fb1",
   "language": "python",
   "display_name": "PyCharm (ai_quant_trade)"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}